package org.unidata.mdm.dq.core.service.impl.instance;

import java.util.Objects;

import org.apache.commons.lang3.tuple.Pair;
import org.unidata.mdm.dq.core.context.CleanseFunctionContext;
import org.unidata.mdm.dq.core.dto.CleanseFunctionResult;
import org.unidata.mdm.dq.core.service.impl.CleanseFunctionCacheComponent;
import org.unidata.mdm.dq.core.service.impl.function.system.AbstractSystemCleanseFunction;
import org.unidata.mdm.dq.core.type.cleanse.CleanseFunction;
import org.unidata.mdm.dq.core.type.measurement.DqMeasurementCategory;
import org.unidata.mdm.dq.core.type.model.instance.PythonFunctionElement;
import org.unidata.mdm.dq.core.type.model.source.PythonCleanseFunctionSource;
import org.unidata.mdm.system.type.runtime.MeasurementPoint;
import org.unidata.mdm.system.util.TextUtils;

/**
 * @author Mikhail Mikhailov on Jan 28, 2021
 * Java function implementation.
 */
public class PythonCleanseFunctionImpl
    extends AbstractLibraryFunctionImpl<PythonCleanseFunctionSource>
    implements PythonFunctionElement {
    /**
     * Cleanse function implementation.
     */
    private CleanseFunction cleanseFunction;
    /**
     * Constructor.
     * @param acfs
     */
    public PythonCleanseFunctionImpl(PythonCleanseFunctionSource pcfs) {
        super(pcfs);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isPythonFunction() {
        return true;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public PythonFunctionElement getPythonFunction() {
        return this;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public CleanseFunctionResult execute(CleanseFunctionContext ctx) {
        MeasurementPoint.start(DqMeasurementCategory.PYTHON_CLEANSE_FUNCTION.name(), ctx.getFunctionName());

        try {
            return Objects.isNull(cleanseFunction) ? null : cleanseFunction.execute(ctx);
        } finally {
            MeasurementPoint.stop();
        }
    }
    /*
     * Sets the function implementation and calculates state.
     */
    public void implement(String storageId, CleanseFunctionCacheComponent cfcc) {

        Pair<CleanseFunction, Exception> result = cfcc.find(storageId, this);

        CleanseFunction function = result.getKey();
        Exception exception = result.getValue();

        // Collect flags
        boolean system = false;
        boolean configurable = true;
        boolean ready = Objects.nonNull(function);

        if (ready) {

            system = function instanceof AbstractSystemCleanseFunction;
            configurable = Objects.isNull(function.configure());
            this.cleanseFunction = function;

            // Add port definitions
            if (!configurable) {

            }
        }

        if (Objects.nonNull(exception)) {
            source.setNote(TextUtils.getText(exception));
        }

        source
            .withReady(ready)
            .withSystem(system)
            .withConfigurable(configurable);
    }
}
